package main

import (
	"bufio"
	"fmt"
	"io"
	"log"
	"net"
	"os"
	"path/filepath"
	"strings"
	"sync"
)

type FTPServer struct {
	RootDir string
	Conn    io.ReadWriteCloser
	Logger  *log.Logger
	wg      sync.WaitGroup
}

func NewFTPServer(rootDir string, conn io.ReadWriteCloser, logger *log.Logger, wg *sync.WaitGroup) *FTPServer {
	return &FTPServer{
		RootDir: rootDir,
		Conn:    conn,
		Logger:  logger,
		wg:      *wg,
	}
}

func (s *FTPServer) HandleCommands() {
	defer s.Conn.Close()
	defer s.wg.Done()

	scanner := bufio.NewScanner(s.Conn)
	for scanner.Scan() {
		cmdStr := scanner.Text()
		s.Logger.Println("Received command: " + cmdStr)
		cmd, arg := parseCommand(cmdStr)

		switch strings.ToUpper(cmd) {
		case "CD":
			s.changeDirectory(arg)
		case "LS":
			s.listDirectory(arg)
		case "GET":
			s.sendFile(arg)
		case "SEND":
			s.receiveFile(arg)
		case "CLOSE":
			return
		default:
			s.sendResponse(fmt.Sprintf("Unknown command: %s", cmdStr))
		}
	}
}

func parseCommand(command string) (string, string) {
	parts := strings.Fields(command)
	if len(parts) > 0 {
		cmd := parts[0]
		if len(parts) > 1 {
			arg := parts[1]
			return cmd, arg
		}
		return cmd, ""
	}
	return "", ""
}

func (s *FTPServer) changeDirectory(directory string) {
	fullPath := filepath.Join(s.RootDir, directory)
	_, err := os.Stat(fullPath)
	if err == nil {
		os.Chdir(fullPath)
		s.sendResponse("Changed directory to " + directory)
	} else {
		s.sendResponse("Directory does not exist: " + directory)
	}
}

func (s *FTPServer) listDirectory(directory string) {
	fullPath := filepath.Join(s.RootDir, directory)
	files, err := os.ReadDir(fullPath)
	if err == nil {
		var fileList []string
		for _, file := range files {
			fileList = append(fileList, file.Name())
		}
		s.sendResponse(strings.Join(fileList, "\n"))
	} else {
		s.sendResponse("Directory does not exist: " + directory)
	}
}

func (s *FTPServer) sendFile(fileName string) {
	filePath := filepath.Join(s.RootDir, fileName)
	file, err := os.Open(filePath)
	if err == nil {
		_, err := io.Copy(s.Conn, file)
		if err == nil {
			s.sendResponse("File sent successfully")
		} else {
			s.sendResponse("Error sending file: " + err.Error())
		}
	} else {
		s.sendResponse("File does not exist: " + fileName)
	}
}

func (s *FTPServer) receiveFile(fileName string) {
	filePath := filepath.Join(s.RootDir, fileName)
	file, err := os.Create(filePath)
	if err == nil {
		_, err := io.Copy(file, s.Conn)
		if err == nil {
			s.sendResponse("File received successfully")
		} else {
			s.sendResponse("Error receiving file: " + err.Error())
		}
	} else {
		s.sendResponse("Error creating file: " + err.Error())
	}
}

func (s *FTPServer) sendResponse(message string) {
	_, err := io.WriteString(s.Conn, message+"\n")
	if err != nil {
		s.Logger.Println("Error sending response: " + err.Error())
	}
}

func main() {
	// 初始化日志
	file, err := os.OpenFile("server.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
	if err != nil {
		fmt.Println("Error opening log file:", err)
	}
	defer file.Close()

	logger := log.New(file, "", log.LstdFlags)

	// 创建并启动服务器
	wg := sync.WaitGroup{}

	listen, err := net.Listen("tcp", "localhost:2121")
	if err != nil {
		fmt.Println("Error connecting: ", err)
		return
	}
	conn, err := listen.Accept()
	if err != nil {
		fmt.Println("Error Accept: ", err)
		return
	}
	defer conn.Close()

	server := NewFTPServer("./ftp", conn, logger, &wg)
	wg.Add(1)
	go server.HandleCommands()

	wg.Wait()
}
